package scu.maqiang.cartesiancfd;

import scu.maqiang.numeric.MVO;

import java.io.*;
import java.util.Arrays;
import java.util.Vector;

class Point {
    public double x;
    public double y;
}

public class CartesianMesh2D {
    /**
     * 区域名称
     */
    private String GeometryName;
    /**
     * 初始区域X方向最小值
     */
    private double Xmin;
    /**
     * 初始区域X方向最大值
     */
    private double Xmax;
    /**
     * 初始区域Y方向最小值
     */
    private double Ymin;
    /**
     * 初始区域Y方向最大值
     */
    private double Ymax;
    /**
     * 空间步长
     */
    private double h;
    /**
     * x方向比例
     */
    private double x_factor;
    /**
     * 初始网格m行, 从下到上
     */
    private int m;
    /**
     * 初始网格n列, 从左到右
     */
    private int n;
    /**
     * 总初始网格数
     */
    private int total;
    /**
     * 是否续算, 外流/内流
     */
    boolean iflag_restar;
    /**
     * 是否几何适应加密
     */
    boolean iflag_GeoAdapt;
    /**
     * 是否仅输出网格
     */
    boolean iflag_MeshOnly;
    /**
     * 是否仅输出外部网格
     */
    boolean iflag_OnlyOutNScell;
    /**
     * 初始网格
     */
    public  CartesianCell[] cell;

    /**
     * 几何外形区域
     */
    public double[][] GeometryEntity;
    /**
     * 缓冲层数
     */
    int BufferLayerLVL;
    /**
     * 加密最大次数
     */
    int lvlmax;
    /**
     * 解自适应加密次数AMR
     */
    int lvlAMR;
    /**
     * 加密尺寸
     */
    double[] refinesize;
    /**
     * 网格结点个数
     */
    public int nNode = 0;
    /**
     * 网格单元个数
     */
    public int nElement = 0;

    /**
     * 存储网格节点信息
     */
    public double[][] Node;

    /**
     * 存留变量列表
     */
    public Vector<double[]> cVariables;

    public CartesianMesh2D(double[] range, double size, double xFactor, boolean iflag_MeshOnly, String geometryFile) {
        Xmin = range[0];
        Xmax = range[1];
        Ymin = range[2];
        Ymax = range[3];
        h = size;
        x_factor = xFactor;
        m = (int) ((Xmax - Xmin) / (x_factor * h));
        n = (int) ((Ymax - Ymin) / h);
        //total为初始网格总数
        total = m * n;

        System.out.println("Read file " + geometryFile);
        try(BufferedReader br = new BufferedReader(new FileReader(geometryFile))) {
            String line = br.readLine();
            int noPoint2D = Integer.parseInt(line);
            GeometryEntity = new double[noPoint2D][];
            for(int i = 0; i < noPoint2D; ++i) {
                GeometryEntity[i] = new double[2];
                line = br.readLine();
                String[] tokens = line.split("\\s+");
                GeometryEntity[i][0] = Double.parseDouble(tokens[0]);
                GeometryEntity[i][1] = Double.parseDouble(tokens[1]);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        System.out.println("Create Background Mesh!");

        cell = new CartesianCell[total];
        for(int i = 0; i < total; i++) {
            cell[i] = new CartesianCell();
            cell[i].num[0] = i / m;
            cell[i].num[1] = i % m;
            cell[i].lvl = 0;
            cell[i].centerPoint[0] = Xmin + (cell[i].num[1] + 0.5) * x_factor * h;
            cell[i].centerPoint[1] = Ymin + (cell[i].num[0] + 0.5) * h;
            cell[i].sp = 0;  //初始无子结点

            double tx = cell[i].centerPoint[0];
            double ty = cell[i].centerPoint[1];
            cell[i].sort = gridSort(tx, ty); //判断单元是否在物面内

            cell[i].father = null;
            double clvl = cell[i].lvl;
            cell[i].dw = miwall(cell[i]);
            cell[i].cross = gridcross(cell[i]);
            cell[i].son = null;
        }
        System.out.println("Background mesh done");

        if (iflag_restar) {
            System.out.println("Read restar_mesh file");
            restar_creatmesh();
        } else if (iflag_GeoAdapt) {
            System.out.println("Start Geometric adaptation");
            GeoAdapt();
        }
    }

    /**
     * 使用射线法判断单元是否在单元内
     * @param x0
     * @param y0
     * @return 在物面内为1, 物理外为0
     */
    public int gridSort(double x0, double y0) {
        double[] a = new double[3];
        double[] t = new double[3];
        double[] d = new double[] {1.123, -1.123, 2.345};
        int mm = 0;
        int nn = 0;
        int counter = 0;
        int dmax = GeometryEntity.length;
        double[] xd = MVO.col(GeometryEntity, 0);
        double[] yd = MVO.col(GeometryEntity, 1);
        for (int i = 0; i < 3; i++) {
            counter = 0;
            for(int j = 0; j < dmax - 1; j++) {
                a[i] = (yd[j + 1] - y0 - (xd[j + 1] - x0) * d[i]) / ((xd[j] - xd[j + 1]) * d[i] - yd[j] + yd[j + 1]);
                if (a[i] > 0 && a[i] <= 1) {
                    t[i] = xd[j + 1] - x0 + a[i] * (xd[j] - xd[j + 1]);
                    if (t[i] >= 0) {
                        counter = counter + 1;
                    }
                }
            }
            if (counter % 2 == 0) {
                mm++;
            } else {
                nn++;
            }
        }

        if (mm > nn) {
            return 0;
        } else {
            return 1;
        }
    }

    /**
     * 输入一个网格节点，先得到四个顶点的坐标，然后判断四个顶点在物体内部还是外部
     * @param cell
     * @return
     */
    public int gridcross(CartesianCell cell) {
        double lvl = cell.lvl;
        double cx = cell.centerPoint[0];
        double cy = cell.centerPoint[1];
        double LL = Math.pow(2, lvl + 1);
        double xx1 = cx - x_factor * h / LL;
        double yy1 = cy - h / LL;
        double xx2 = cx + x_factor * h / LL;
        double yy2 = cy - h / LL;
        double xx3 = cx - x_factor * h / LL;
        double yy3 = cy + h / LL;
        double xx4 = cx + x_factor * h / LL;
        double yy4 = cy + h / LL;

        if( cell.num[0] < 3.0 ) {
            return -1;
        } else if(cell.num[1] > m - 2  && (cell.num[0] > 2.0 && cell.num[0] < n - 1)) {
            return -2;
        } else if (cell.num[0] > n - 2) {
            return -3;
        } else if (cell.num[1] < 3 && (cell.num[0] > 2 && cell.num[0] < n - 1)) {
            return -4;
        } else {
            int t0 = gridSort(cx, cy);
            int t1 = gridSort(xx1, yy1);
            int t2 = gridSort(xx2, yy2);
            int t3 = gridSort(xx3, yy3);
            int t4 = gridSort(xx4, yy4);
            //cross: 0是外部，1外部相交，2内部相交，3是内部
            if (t1 + t2 + t3 + t4 == 4) {
                return 3;
            } else if (t0 == 1) {
                return 2;
            } else {
                if (t1 + t2 + t3 + t4 == 0) {
                    return 0;
                } else {
                    return 1;          //均为0,均在外
                }
            }
        }
    }

    public double miwall(CartesianCell cell) {
        double x0 = cell.centerPoint[0];
        double y0 = cell.centerPoint[1];
        double result = 1e5;
        double a = 1e5;
        int dmax = GeometryEntity.length;
        double[] xd = MVO.col(GeometryEntity, 0);
        double[] yd = MVO.col(GeometryEntity, 1);
        for(int j = 0; j < dmax; ++j) {
            double length = Math.sqrt((xd[j] - xd[j+1]) * (xd[j] - xd[j+1]) + (yd[j] - yd[j+1]) * ((yd[j] - yd[j+1])));
            double cos1 = (x0 - xd[j]) * (xd[j + 1] - xd[j]) + (y0 - yd[j]) * (yd[j+1] - yd[j]);
            double cos2 = (x0 - xd[j+1]) * (xd[j] - xd[j+1]) + (y0 - yd[j+1]) * (yd[j] - yd[j+1]);
            if (cos1 > 0 && cos2 > 0) {
                a = Math.abs((xd[j] - x0) * (yd[j+1] - y0) - (yd[j] - y0) * (xd[j+1] - x0)) / length;
                result = Math.min(a, result);
            } else {
                a = Math.sqrt((xd[j] - x0) * (xd[j] - x0) + (yd[j] - y0) * (yd[j] - y0));
                result = Math.min(a, result);
            }
        }
        return result;
    }

    public void restar_creatmesh() {
        try (BufferedReader br = new BufferedReader(new FileReader("restat_mesh.dat"))){
            for(int i = 0; i < total; ++i) {
                restar_creatmesh_sub(br, cell[i]);
            }
        } catch(IOException e) {
            e.printStackTrace();
        }
    }

    public void restar_creatmesh_sub(BufferedReader br, CartesianCell cell) throws IOException {
        if (Integer.parseInt(br.readLine()) == 0) {
            refine_cell(cell);
            for(int j = 0; j < cell.son.length; ++j) {
                restar_creatmesh_sub(br, cell.son[j]);
            }
        }
    }

    public void refine_cell(CartesianCell cell) {
        //cell.son1 = new CartesianCell();
        //cell.son2 = new CartesianCell();
        //cell.son3 = new CartesianCell();
        //cell.son4 = new CartesianCell();

        double x0 = cell.centerPoint[0];
        double y0 = cell.centerPoint[1];
        cell.son = new CartesianCell[4];

        int sonNum = cell.son.length;
        double xDist = x_factor * h / Math.pow(2, cell.lvl + 2);
        double yDist = h / Math.pow(2, cell.lvl + 2);
        for(int i = 0; i < sonNum; ++i) {
            cell.son[i].father = cell;
            cell.son[i].num = new int[2];
            for(int j = 0; j < cell.num.length; j++) {
                cell.son[i].num[j] = cell.num[j];
            }
            cell.son[i].lvl = cell.lvl + 1;
            cell.son[i].sp = i;
            if (i == 0) {
                cell.son[i].centerPoint = new double[]{x0 - xDist, y0 - yDist};
            } else if (i == 1) {
                cell.son[i].centerPoint = new double[]{x0 + xDist, y0 - yDist};
            } else if (i == 2) {
                cell.son[i].centerPoint = new double[]{x0 + xDist, y0 + yDist};
            } else {
                cell.son[i].centerPoint = new double[]{x0 - xDist, y0 + yDist};
            }
            double xSon = cell.son[i].centerPoint[0];
            double ySon = cell.son[i].centerPoint[1];
            cell.son[i].dw = miwall(cell.son[i]);
            cell.son[i].sort = gridSort(xSon, ySon);
            cell.son[i].cross = gridcross(cell.son[i]);

            cell.son[i].U = cell.U;
            cell.son[i].rot = cell.rot;
            cell.son[i].div = cell.div;

            cell.son[i].mu = cell.mu;
            cell.son[i].mut = cell.mut;
            cell.son[i].dt = cell.dt;
            cell.son[i].utao = cell.utao;

            cell.son[i].Cf = cell.Cf;
            cell.son[i].yp = cell.yp;
            cell.son[i].omg = cell.omg;
            cell.son[i].ddp = cell.ddp;
            cell.son[i].dde = cell.dde;
            cell.son[i].txy = cell.txy;
        }
    }

    public void GeoAdapt() {
        long startTime = System.nanoTime();

        refinesize = new double[lvlmax];
        for(int i = 0; i < lvlmax; ++i) {
            refinesize[i] = BufferLayerLVL * h / (Math.pow(2, i));
        }

        for(int i = 0; i < total; i++) {
            gridrefm(cell[i]);
        }

        //针对相邻网格层次之差大于1的情况，再次细化网格
        //循环lvlmax-1次实现消除网格层次差大于1情况
        for(int j = 0; j < lvlmax - 1; j++) {
            for(int i = 0; i < total; j++) {
                if (cell[i].son[0] == null) {
                    gridmodify(cell[i]);
                }
            }
        }
        long endTime = System.nanoTime();
        System.out.println("Geometric adaptation time: " + (endTime - startTime) / 1e9 + " s");
    }

    public void gridrefm(CartesianCell cell) {
        double dis = miwall(cell);
        for(int i = 0; i < lvlmax; i++) {
            if ((dis <= refinesize[i] && cell.sort == 0 && cell.lvl < i + 1)
                    || (dis <= 0.25 * refinesize[i]) && cell.sort == 1 && cell.lvl < i +1) {
                refine_cell(cell);
                for(int j = 0; j < cell.son.length; ++j) {
                    gridrefm(cell.son[j]);
                }
                return;
            } else if ((dis <= refinesize[i]) && cell.sort == 0 && cell.lvl < lvlmax + 1
                       || (dis <= 0.25 * refinesize[i] && cell.sort == 1 && cell.lvl < lvlmax + 1)) {
                continue;
            } else {
                for(int j = 0; j < cell.son.length; ++j) {
                    cell.son[j] = null;
                }
            }
        }
    }
    public void gridmodify(CartesianCell cell) {
        if (cell.son[0] != null) {
            for(int i = 0; i < cell.son.length; ++i) {
                gridmodify(cell.son[i]);
            }
        } else {
            CartesianCell ct1 = up_neighbor(cell);
            CartesianCell ct2 = down_neighbor(cell);
            CartesianCell ct3 = left_neighbor(cell);
            CartesianCell ct4 = right_neighbor(cell);

            if (ct1 != null) {
                if ((cell.lvl - ct1.lvl) > 1) {
                    refine_cell(ct1);
                }
            }

            if (ct2 != null) {
                if ((cell.lvl - ct2.lvl) > 1) {
                    refine_cell(ct2);
                }
            }
            if (ct3 != null) {
                if ((cell.lvl - ct3.lvl) > 1) {
                    refine_cell(ct3);
                }
            }
            if (ct4 != null) {
                if ((cell.lvl - ct3.lvl) > 1) {
                    refine_cell(ct4);
                }
            }


        }
    }

    /**
     * 初始上邻居
     * @param c 笛卡尔单元
     */
    private CartesianCell init_up_neighbor(CartesianCell c) {
        //如果单元处于最顶层, 则不上邻居单元
        if (c.num[0] == n - 1) {
            return null;
        } else {
            int i = (c.num[0] + 1) * m + c.num[1];
            return cell[i];
        }
    }

    /**
     * 初始下邻居
     * @param c 笛卡尔单元
     */
    private CartesianCell init_down_neighbor(CartesianCell c) {
        //如果单元处于最顶层, 则不上邻居单元
        if (c.num[0] == 0) {
            return null;
        } else {
            int i = (c.num[0] - 1) * m + c.num[1];
            return cell[i];
        }
    }

    /**
     * 初始左邻居
     * @param c 笛卡尔单元
     */
    private CartesianCell init_left_neighbor(CartesianCell c) {
        //如果单元处于最顶层, 则不上邻居单元
        if (c.num[1] == 0) {
            return null;
        } else {
            int i = c.num[0] * m + c.num[1] - 1;
            return cell[i];
        }
    }

    /**
     * 初始左邻居
     * @param c 笛卡尔单元
     */
    private CartesianCell init_right_neighbor(CartesianCell c) {
        //如果单元处于最顶层, 则不上邻居单元
        if (c.num[1] == m - 1) {
            return null;
        } else {
            int i = c.num[0] * m + c.num[1] + 1;
            return cell[i];
        }
    }

    /**
     * 邻居查询上up （下down左left右right）有两种情况，
     * 他们的邻居就是直系，有两种要通过父亲..来找，通过递归找到和自己层级一样的，
     * 或者层级大的但是无子单元的北
     * @param c
     */
    public CartesianCell up_neighbor(CartesianCell c) {
        CartesianCell cellf = c.father;
        if (cellf == null) { //如果c是初始网格, 则可直接找到初始上邻居
            return init_up_neighbor(c);
        } else if (c.sp == 0) {  //0与1 找上邻居都是一个无亲下找就可以
            return cellf.son[3];
        } else if (c.sp == 1) {
            return cellf.son[2];
        }
        CartesianCell cellfn = up_neighbor(cellf);
        if (cellfn != null) {
            //如果上边无子单元，那么3和4的上邻居都是这个大的；如果父亲的上单元有子单元，则再去对应找到
            if (cellfn.son == null) {
                return cellfn;
            } else if (c.sp == 3) {
                return cellfn.son[0];
            } else if (c.sp == 2) {
                return cellfn.son[1];
            }
        }
        return null;
    }

    public CartesianCell down_neighbor(CartesianCell c) {
        CartesianCell cellf = c.father;
        if (cellf == null) { //如果c是初始网格, 则可直接找到初始上邻居
            return init_down_neighbor(c);
        } else if (c.sp == 3) {  //0与1 找上邻居都是一个无亲下找就可以
            return cellf.son[0];
        } else if (c.sp == 2) {
            return cellf.son[1];
        }
        CartesianCell cellfn = down_neighbor(cellf);
        if (cellfn != null) {
            //如果上边无子单元，那么3和4的上邻居都是这个大的；如果父亲的上单元有子单元，则再去对应找到
            if (cellfn.son == null) {
                return cellfn;
            } else if (c.sp == 0) {
                return cellfn.son[3];
            } else if (c.sp == 1) {
                return cellfn.son[2];
            }
        }
        return null;
    }

    public CartesianCell left_neighbor(CartesianCell c) {
        CartesianCell cellf = c.father;
        if (cellf == null) { //如果c是初始网格, 则可直接找到初始上邻居
            return init_left_neighbor(c);
        } else if (c.sp == 1) {  //0与1 找上邻居都是一个无亲下找就可以
            return cellf.son[0];
        } else if (c.sp == 2) {
            return cellf.son[3];
        }
        CartesianCell cellfn = left_neighbor(cellf);
        if (cellfn != null) {
            //如果上边无子单元，那么3和4的上邻居都是这个大的；如果父亲的上单元有子单元，则再去对应找到
            if (cellfn.son == null) {
                return cellfn;
            } else if (c.sp == 3) {
                return cellfn.son[2];
            } else if (c.sp == 0) {
                return cellfn.son[1];
            }
        }
        return null;
    }


    public CartesianCell right_neighbor(CartesianCell c) {
        CartesianCell cellf = c.father;
        if (cellf == null) { //如果c是初始网格, 则可直接找到初始上邻居
            return init_left_neighbor(c);
        } else if (c.sp == 0) {  //0与1 找上邻居都是一个无亲下找就可以
            return cellf.son[1];
        } else if (c.sp == 3) {
            return cellf.son[2];
        }
        CartesianCell cellfn = right_neighbor(cellf);
        if (cellfn != null) {
            //如果上边无子单元，那么3和4的上邻居都是这个大的；如果父亲的上单元有子单元，则再去对应找到
            if (cellfn.son == null) {
                return cellfn;
            } else if (c.sp == 1) {
                return cellfn.son[0];
            } else if (c.sp == 2) {
                return cellfn.son[3];
            }
        }
        return null;
    }

    /**
     * 确定各个单元的邻居
     */
    public void idneighbor() {
        for(int i = 0; i < total; i++) {
            idnei(cell[i]);
        }
    }

    /**
     * 确定一个单元的邻居
     * @param c
     */
    public void idnei(CartesianCell c) {
        CartesianCell ct1 = up_neighbor(c);
        CartesianCell ct2 = down_neighbor(c);
        CartesianCell ct3 = left_neighbor(c);
        CartesianCell ct4 = right_neighbor(c);

        c.upnei = ct1;
        c.downnei = ct2;
        c.leftnei = ct3;
        c.rightnei = ct4;

        if (c.son != null) {
            for(int i = 0; i < c.son.length; ++i) {
                idnei(c.son[i]);
            }
        }
    }


    public void toTecplot(String fileName) {
        try(BufferedWriter bw = new BufferedWriter(new FileWriter(fileName))) {
            Node = new double[10000000][];
            for(int i = 0; i < 10000000; i++) {
                Node[i]= new double[2];
            }
            nodeInfomation();
            cVariables = new Vector<>();
            meshInfomation();

            System.out.println("Outputting Mesh data to file:" + fileName);
            System.out.println("ZONE Element = " + nElement + "  Node = " + nNode);

            bw.write("TITLE = \"2D mesh Results\"\n");
            bw.write("VARIABLES = \"X\", \"Y\", \"sort\", \"cross\", \"dw\"\n");
            bw.write("ZONE N = " + nNode + " E = " + nElement + "  ZONETYPE=FEQUADRILATERAL\n");
            bw.write("DATAPACKING=BLOCK\n");
            bw.write("VARLOCATION=([1-2]=NODAL, [3-5]=CELLCENTERED)\n");
            for(int i = 0; i < nNode; i++) {
                bw.write(Node[i][0] + "\n");
            }
            for(int i = 0; i < nNode; i++) {
                bw.write(Node[i][1] + "\n");
            }
            int Noutcell = cVariables.size();
            for(int j = 0; j < 3; j++) {
                for(int i = 0; i < Noutcell; ++i) {
                    bw.write(cVariables.elementAt(i)[j] + "\n");
                }
            }

            for(int i = 0; i < total; i++) {
                if (iflag_OnlyOutNScell && cell[i].cross < 0) {
                    continue;
                }
                link(cell[i], bw);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void nodeInfomation() {
        nNode = 0;
        nElement = 0;
        for(int i = 0; i < total; ++i) {
            if (iflag_OnlyOutNScell && cell[i].cross < 0) {
                continue;
            }
            initial_node(cell[i]);
        }
        for(int i = 0; i < total; ++i) {
            if (iflag_OnlyOutNScell && cell[i].cross < 0) {
                continue;
            }
            addnode(cell[i]);
        }
    }

    public int meshInfomation() {
        int Noutcell = 0;
        for(int i = 0; i < total; ++i) {
            if (iflag_OnlyOutNScell && cell[i].cross < 0) {
                continue;
            }
            save_mesh_var(cell[i]);
        }
        return Noutcell;
    }

    public void link(CartesianCell c, BufferedWriter bw) throws IOException {
        if (c.son != null) {
            for(int i = 0; i < 4; i++) {
                link(c.son[i], bw);
            }
        } else {
            if (iflag_OnlyOutNScell && (c.cross < 0 || c.cross > 1)) {
                bw.write(c.cnode[0] + "  " + c.cnode[1] + "  " + c.cnode[2] + "  " + c.cnode[3] + "\n");
            }
        }
    }

    public void save_mesh_var(CartesianCell c) {
        if (c.son != null) {
            for(int i = 0; i < 4; i++) {
                save_mesh_var(c.son[i]);
            }
        } else {
            if (iflag_OnlyOutNScell && (c.cross < 0 || c.cross > 1)) {
                cVariables.add(new double[]{c.sort, c.cross, c.dw});
            }
        }
    }
    /**
     * 初始化每个单元顶点
     * @param c
     */
    private void initial_node(CartesianCell c) {
        if (c.son == null) {
            Arrays.fill(c.cnode, 0);
        } else {
            for(int i = 0; i < c.son.length; ++i) {
                initial_node(c.son[i]);
            }
        }
    }

    public void addnode(CartesianCell c) {
        int i = 0;
        if (c.son != null) {
            addnode(c.son[0]);
            addnode(c.son[1]);
            addnode(c.son[3]);
            addnode(c.son[2]);
            c.cnode[0] = c.son[0].cnode[0];
            c.cnode[1] = c.son[1].cnode[1];
            c.cnode[2] = c.son[2].cnode[2];
            c.cnode[3] = c.son[3].cnode[3];
        } else {
            CartesianCell cd = c.downnei;
            CartesianCell cl = c.leftnei;
            if (iflag_OnlyOutNScell) {
                if (c.cross < 0 || c.cross > 1) {
                    return ;
                }
                if ((cl.cross == 0 || cl.cross == 1) && (cd.cross == 0 || cd.cross == 1)) {
                    i = 1;
                } else if ((cl.cross == 0 || cl.cross == 1) && (cd.cross < 0 || cd.cross > 1)) {
                    i = 2;
                } else if ((cl.cross < 0 || cl.cross > 1) && (cd.cross == 0 || cd.cross == 1)) {
                    i = 3;
                } else if ((cl.cross < 0 || cl.cross > 1) && (cd.cross < 0 || cd.cross > 1)) {
                    i = 0;
                }
            } else {
                if (cl != null && cd != null) {
                    i = 1;
                } else if (cl != null && cd == null) {
                    i = 2;
                } else if (cl == null && cd == null) {
                    i = 3;
                } else {
                    i = 0;
                }
            }
            addleafnode(c, cl, cd, i);
        }
    }

    /**
     * TODO 还要写如果加叶子节点
     * @param c
     * @param cl
     * @param cd
     * @param i
     *
     */
    public void addleafnode(CartesianCell c, CartesianCell cl, CartesianCell cd, int i) {
        switch (i) {
            case 0:
                nElement = nElement + 1;
                nNode = nNode + 4;
                c.cnode[0] = nNode - 3;
                c.cnode[1] = nNode - 2;
                c.cnode[2] = nNode - 1;
                c.cnode[3] = nNode;

                break;
            case 1:
                break;
            case 2:
                break;
            case 3:
                break;
            default:
                System.out.println("Wrong value");
                break;
        }
    }

    public static void main(String[] args) {

    }


}
